import datetime
from typing import Union

from elasticsearch import Elasticsearch
from sqlalchemy.orm import Session

from app.monitor_logs.models.monitor_log_policy import MonitorLogPolicy
from app.monitor_logs.models.monitor_log_exclude_keyword import MonitorLogExcludeKeyword
from app.monitor_logs.handlers.dsl_handler import abnormal_service_agg_query, abnormal_service_count_query, abnormal_service_log_query
from app.monitor_logs.handlers.character_handler import character_log_output


def get_abnormal_service(es_client: Elasticsearch, index: str, log_level: str, cst_begin_time: str, cst_end_time: str, session: Session):
    """
    获取异常服务列表信息
    :param es_client:
    :param index:
    :param log_level:
    :param cst_begin_time:
    :param cst_end_time:
    :param session:
    :return:  {abnormal_server:异常服务, exclude_k_abnormal_count:排查关键字异常数量, cst_begin_time:查询开始时间, cst_end_time:查询结束时间, character_log: 异常特征日志 }
    """
    abnormal_server_res = abnormal_service_agg_query(es_client=es_client, index=index, cst_begin_time=cst_begin_time,
                                                     cst_end_time=cst_end_time, log_level=log_level)
    print(abnormal_server_res)
    res = []
    for abnormal_server, abnormal_count in abnormal_server_res.items():
        judge_res, exclude_keywords, exclude_k_abnormal_count = judge_alarm_threshold(abnormal_server, abnormal_count, session, es_client,
                                                                                      index, log_level, cst_begin_time, cst_end_time)
        if judge_res:
            data = abnormal_service_log_query(es_client, index, abnormal_server, cst_begin_time, cst_end_time, log_level, exclude_keywords)
            character_log = character_log_output(data)
            res.append({"abnormal_server": abnormal_server, "exclude_k_abnormal_count": exclude_k_abnormal_count,
                        "cst_begin_time": cst_begin_time, "cst_end_time": cst_end_time, "character_log": character_log,
                        "exclude_keywords": exclude_keywords})
    return res


def judge_alarm_threshold(abnormal_server: str, abnormal_count: int, session: Session, es_client: Elasticsearch, index: str, log_level: str,
                          cst_begin_time: str, cst_end_time: str, default_alarm_threshold: int = 50) -> (bool, Union[list, None]):
    # 初步判断: 服务的错误数量与告警阈值对比, 生成应用服务列表
    service_policy = MonitorLogPolicy.get_policy_by_service_name(session, abnormal_server)
    alarm_threshold = service_policy.get('alarm_threshold', default_alarm_threshold)
    if abnormal_count >= alarm_threshold:
        print(abnormal_server)
        # 进一步判断: 排除已知错误关键字获取服务错误数量,判断关键字生效时间
        current_datetime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        exclude_keywords = MonitorLogExcludeKeyword.get_exclude_keyword_by_service_name(session, abnormal_server, current_datetime)
        exclude_keywords = [item['exclude_keyword'] for item in exclude_keywords if exclude_keywords]

        exclude_k_abnormal_count = abnormal_service_count_query(es_client=es_client, index=index, service=abnormal_server,
                                                                cst_begin_time=cst_begin_time, cst_end_time=cst_end_time,
                                                                log_level=log_level, exclude_keywords=exclude_keywords)
        if exclude_k_abnormal_count >= alarm_threshold:
            return True, exclude_keywords, exclude_k_abnormal_count
    return False, None, None


if __name__ == '__main__':
    import datetime
    from datetime import timedelta
    from common.database import SessionLocal
    from common.elastic import get_es

    now = datetime.datetime.now()
    interval_min = 5
    i = 'logstash-applog*'
    level = "ERROR"
    cst_begin = (now - timedelta(minutes=interval_min)).strftime("%Y-%m-%d %H:%M:%S")
    cst_end = now.strftime("%Y-%m-%d %H:%M:%S")
    es = get_es()
    db = SessionLocal()
    print(get_abnormal_service(es_client=es, index=i, cst_begin_time=cst_begin, cst_end_time=cst_end, log_level=level, session=db))
    db.close()